<?php

uses('sanitize');

class QuotesController extends AppController
{
	var $name = 'Quotes';
	var $uses = array('Quote', 'Vote');
	var $helpers = array('Html', 'Time', 'Form');
	var $paginate = array('limit' => QDB_PAGE_LIMIT, 'order' => 'Quote.id DESC');

	function process($data)
	{
		$data = eregi_replace("^(re: [^\n]*)\n", "[h]\\1[/h]", $data);
		$data = str_replace("\n", '<br />', $data);
		$data = preg_replace('/\[link=(.*)\](.*)\[\/link\]/Ui', '<a href="\1">\2</a>', $data);
		$data = ereg_replace('(^|[^"])((https?|ftp|irc)://[^<>[:space:]]+[[:alnum:]/;])', '\1<a href="\2">\2</a>', $data);

		$data = preg_replace('/\[abbr=(.*)\](.*)\[\/abbr\]/Ui', '<acronym title="\1">\2</acronym>', $data);
		$data = preg_replace('/\[h\](.*)\[\/h\]/Ui', '<h2>\1</h2>', $data);
		$data = preg_replace('/\[s\](.*)\[\/s\]/Ui', '<del>\1</del>', $data);
		$data = preg_replace('/\[b\](.*)\[\/b\]/Ui', '<strong>\1</strong>', $data);
		$data = preg_replace('/\[i\](.*)\[\/i\]/Ui', '<em>\1</em>', $data);
		$data = preg_replace('/\[u\](.*)\[\/u\]/Ui', '<span class="quote-u">\1</span>', $data);

		$opening = 0;
		$closing = 0;

		$data = preg_replace('/\[quote=?.*\]/Ui', '<blockquote>', $data, -1, $opening);
		$data = str_ireplace('[/quote]', '</blockquote>', $data, $closing);

		$common = min($opening, $closing);
		
		for($opening -= $common; $opening > 0; $opening--)
			$data = '<blockquote>' . $data;
		
		for($closing -= $common; $closing > 0; $closing--)
			$data = $data . '</blockquote>';

		return $data;
	}

	function sanitize($quote)
	{
		$sanitize = new Sanitize();

		$quote['Quote']['body'] = $this->process($sanitize->html($quote['Quote']['body']));
		$quote['Quote']['notes'] = $this->process($sanitize->html($quote['Quote']['notes']));
		$quote['Quote']['tags'] = $sanitize->html($quote['Quote']['tags'], true);
		$quote['Quote']['created'] = strtotime($quote['Quote']['created']);
		$quote['Quote']['deleted'] = strtotime($quote['Quote']['deleted']);
		
		return $quote;
	}

	function sanitizeSave($quote)
	{
		$sanitize = new Sanitize();
		$quote['Quote']['tags'] = $sanitize->paranoid(strtolower($quote['Quote']['tags']),
			array(' ', '-', '_'));
		
		return $quote;
	}

	function index()
	{
		$quotes = $this->paginate('Quote', array('status = ' => QUOTE_STATUS_NORMAL));
			
		foreach($quotes as &$quote)
		{
			$quote = $this->sanitize($quote);
		}
		
		$this->set('header', 'Browse quotes');
		$this->set('action', 'index');
		$this->set('quotes', $quotes);
		$this->set('title', 'Quote index');
	}

	function rss($count = QDB_PAGE_LIMIT)
	{
		$quotes = $this->Quote->findAll("status = '" . QUOTE_STATUS_NORMAL . "'", null, 'Quote.id DESC', $count);
		
		foreach($quotes as &$quote)
		{
			$quote = $this->sanitize($quote);
		}
		
		$coreUrl = $this->getCoreUrl();
		
		header('Content-type: application/rss+xml; charset=utf-8');
		header('Content-disposition: inline; filename=rss.xml');
		$this->layout = 'blank';
		$this->set('quotes', $quotes);
		$this->set('generator', QDB_NAME);
		$this->set('desc', QDB_NAME);
		$this->set('url', $coreUrl);
		$this->set('lang', 'en');
		$this->set('email', QDB_WEBMASTER_EMAIL);
		$this->render('rss');
	}

	function top()
	{
		$this->paginate['order'] = 'score DESC';
		$quotes = $this->paginate('Quote', array('status = ' => QUOTE_STATUS_NORMAL));

		foreach($quotes as &$quote)
		{
			$quote = $this->sanitize($quote);
		}
		
		$this->set('header', 'Top quotes');
		$this->set('title', 'Top quotes');
		$this->set('quotes', $quotes);
		$this->render('index');
	}

	function bottom()
	{
		$this->paginate['order'] = 'score ASC';
		$quotes = $this->paginate('Quote', array('status = ' => QUOTE_STATUS_NORMAL));
				
		foreach($quotes as &$quote)
		{
			$quote = $this->sanitize($quote);
		}
		
		$this->set('header', 'Bottom quotes');
		$this->set('title', 'Bottom quotes');
		$this->set('quotes', $quotes);
		$this->render('index');
	}

	function mostvoted()
	{
		$this->paginate['order'] = 'votes DESC';
		$quotes = $this->paginate('Quote', array('status = ' => QUOTE_STATUS_NORMAL));

		foreach($quotes as &$quote)
		{
			$quote = $this->sanitize($quote);
		}
		
		$this->set('header', 'Quotes with most votes');
		$this->set('title', 'Quotes with most votes');
		$this->set('quotes', $quotes);
		$this->render('index');
	}

	function search($term = null)
	{
		if(!$term)
		{
			$term = $this->params['url']['term'];
			
			if(!$term)
			{
			    $this->redirect('/quotes');
			}
			else if(!ereg('[/:]', $term))
			{
			    $this->redirect('/quotes/search/' . urlencode($term));
			}
		}
		
		$sanitize = new Sanitize();
		$sqlterm = $sanitize->escape($term);
		$cond = array('and' => array('status = ' => QUOTE_STATUS_NORMAL, 'or' => array(
			"body LIKE '%" . $sqlterm . "%'",
			"notes LIKE '%" . $sqlterm . "%'")));

		$quotes = $this->paginate('Quote', $cond);

		foreach($quotes as &$quote)
		{
			$quote = $this->sanitize($quote);
		}
		
		$this->set('header', 'Search: ' . $term);
		$this->set('quotes', $quotes);
		$this->render('index');
	}

	function tag($tag = null, $page = 1)
	{
		if(!$tag)
		{
			$this->redirect('/quotes');
			exit();
		}
		
		$sanitize = new Sanitize();
		$sqltag = $sanitize->escape($tag);
		
		$cond = array('and' => array("status = " => QUOTE_STATUS_NORMAL, 'or' => array(
			"tags = '" . $sqltag . "'",
			"tags LIKE '% " . $sqltag . "'",
			"tags LIKE '" . $sqltag . " %'",
			"tags LIKE '% " . $sqltag . " %'")));
		
		$quotes = $this->paginate('Quote', $cond);	

		foreach($quotes as &$quote)
		{
			$quote = $this->sanitize($quote);
		}
		
		$this->set('header', 'Tag: ' . $tag);
		$this->set('quotes', $quotes);
		$this->render('index');
	}

	function random($randomcount = QDB_RANDOM_COUNT)
	{
		$quotes = $this->Quote->findAll("status = '" . QUOTE_STATUS_NORMAL . "'");
		$count = sizeof($quotes);
		$randomcount = min($count, $randomcount);
		$random = array();
		$selected = array();
		
		for($i = 0; $i < $randomcount; $i++)
		{
			while(true)
			{
				$value = rand(0, $count - 1);
				$exists = false;
				
				for($j = 0; $j < $i; $j++)
				{
					if($random[$j] == $value)
					{
						$exists = true;
						break;	
					}
				}
				
				if(!$exists)
				{
					$random[] = $value;
					break;
				}
			}
		}
		
		foreach($random as $i)
		{
			$selected[] = $this->sanitize($quotes[$i]);
		}
		
		$this->set('header', $randomcount == 1 ? 'Random quote' : 'Random quotes');
		$this->set('quotes', $selected);
		$this->set('title', 'Random quotes');
		$this->render('index');
	}

	function view($id)
	{
		$this->Quote->id = $id;
		$quote = $this->Quote->read();
		
		if(!$quote)
		{
		$this->flash('Quote #' . $id . ' was deleted as spam.', '/quotes');
		}
		
		$quote = $this->sanitize($quote);
		
		$this->set('header', 'View quote');
		$this->set('title', 'View quote #' . $id);
			$this->set('quotes', array($quote));
			$this->render('index');
	}

	function rawpreview()
	{
		$this->data['Quote']['id'] = -1;
		$this->data['Quote']['author_id'] = '';
		$this->data['Quote']['author_ip'] = '';
		$this->data['Quote']['score'] = '';
		$this->data['Quote']['created'] = '';
		$this->data['Quote']['deleted'] = '';
		$this->quote = $this->sanitize($this->data);
		$this->set('header', 'preview');
		$this->set('quotes', array(array('Quote' => $this->quote['Quote'])));
		$this->layout = 'blank';
		$this->render('index');
	}

	function add()
	{
		$this->checkLock();

		if(!empty($this->data['Quote']))
		{
			if(strpos($this->data['Quote']['body'], '<a href') !== false)
			{
			    $this->flash('Oops, something vague has happened!', '/quotes');
			}
		
			$this->data = $this->sanitizeSave($this->data);
			
			if($this->isAdmin)
				$this->data['Quote']['status'] = QUOTE_STATUS_NORMAL;
		
			if(isset($_POST['quote-edit-preview']))
			{
				$this->data['Quote']['id'] = -1;
				$this->data['Quote']['author_id'] = '';
				$this->data['Quote']['author_ip'] = '';
				$this->data['Quote']['score'] = '';
				$this->data['Quote']['created'] = '';
				$this->data['Quote']['deleted'] = '';
				$this->set('quotes', array($this->sanitize($this->data)));
			}
			else
			{
				if($this->isLoggedIn())
				    $this->data['Quote']['author_id'] = $this->getUserID();
				
				$this->data['Quote']['author_ip'] = $this->getUserIP();
			
				if($this->Quote->save($this->data['Quote']))
				{
					$this->flash($this->isAdmin ? 'Your quote has been added.' : 'Your quote has been placed into the moderation queue.', '/quotes/');
					exit();
				}
			}
		}
		
		$this->set('header', 'Add quote');
		$this->set('title', 'Add quote');
	}

	function edit($id)
	{
		$this->checkLock();
		$this->checkRights();

		if(empty($this->data['Quote']))
		{
			$this->Quote->id = $id;
			$this->data = $this->Quote->read();
		}
		else
		{
			$this->data = $this->sanitizeSave($this->data);
		
			if(isset($_POST['quote-edit-preview']))
			{
				$this->data['Quote']['id'] = -1;
				$this->set('quotes', array($this->sanitize($this->data)));
			}
			else
			{
				$this->data['Quote']['id'] = $id;
			
				if($this->Quote->save($this->data['Quote']))
				{
					$this->flash('Your quote has been updated.', '/' . $id);
					exit();
				}
			}
		}
		
		$this->set('header', 'Edit quote #' . $id);
		$this->set('title', 'Edit quote #' . $id);
		$this->render('add');
	}

	function ajaxvote($id, $direction)
	{
		$this->checkLock();
		$score = null;
		$this->set('result', $this->_voteReal($id, $direction, $score));
		$this->set('score', $score);
		$this->layout = 'blank';
	}

	function vote($id, $direction)
	{
		$this->checkLock();
		$score = null;
		$result = $this->_voteReal($id, $direction, $score);
		$this->flash($result ? $result : 'Your vote has been cast (new score: ' . $score[0] . '/' . $score[1] . ')', '/quotes');
	}

	function _voteReal($id, $direction, &$retval)
	{
		if($direction == 'up')
		{
			$offset = 1;
		}
		else if($direction == 'down')
		{
			$offset = -1;
		}
		else
		{
			return 'Invalid direction.';
		}
		
		$ip = $_SERVER['REMOTE_ADDR'];
		
		if(!$this->Quote->findCount(array('Quote.id' => $id)))
		{
			return 'The quote with this ID does not exist.';
		}
		
		if($this->Vote->findCount(array('quote_id' => $id, 'ip' => $ip)) > 0)
		{
			return 'Your cannot vote for the same quote more than once.';
		}
		
		$this->Quote->id = $id;
		$quote = $this->Quote->read();
		$quote['Quote']['votes']++;
		$quote['Quote']['score'] += $offset;

		if($this->Quote->save($quote))
		{
			$vote = array('Vote' => array());
			$vote['Vote']['quote_id'] = $id;
			$vote['Vote']['ip'] = $ip;
			
			$this->Vote->save($vote);
			
			$score = $quote['Quote']['score'];
			
			if($quote['Quote']['score'] > 0)
			$score = '+' . $score;
			
			$retval = array($score, $quote['Quote']['votes']);
			return null;
		}
		else
		{
			return 'An error occurred when attempting to change the score.';
		}
	}

	function tags($format = 'html')
	{
		$quotes = $this->Quote->findAll("status = '" . QUOTE_STATUS_NORMAL . "'");
		$tags = array();
		
		foreach($quotes as $quote)
		{
			$list = explode(' ', $quote['Quote']['tags']);
			
			foreach($list as $tag)
			{
				$tag = trim($tag);
			
				if($tag != '')
				{
					if(!isset($tags[$tag]))
						$tags[$tag] = 0;
				
					$tags[$tag]++;
				}
			}
		}

		ksort($tags);
		$this->set('title', 'Tags');
		$this->set('tags', $tags);
		
		if($format == 'xml')
		{
			$this->layout = 'xml';
			$this->render('xmltags');
		}
	}

	function delete($id)
	{
		$this->checkLock();
		$this->checkRights();

		$this->Quote->id = $id;
		$quote = $this->Quote->read();
		$quote['Quote']['status'] = QUOTE_STATUS_DELETED;
		$quote['Quote']['deleted'] = date('Y-m-d H:i:s');
			
		if($this->Quote->save($quote))
		{
				$this->flash('Quote deleted.', '/' . $id);
				exit();
		}

		$this->flash('Error deleting quote.', '/' . $id);
	}

	function spam($id)
	{
		$this->checkLock();
		$this->checkRights();

		if($this->Quote->del($id))
		{
				$this->flash('Quote deleted.', '/');
				exit();
		}

		$this->flash('Error deleting quote.', '/' . $id);
	}

	function undelete($id)
	{
		$this->checkLock();
		$this->checkRights();

		$this->Quote->id = $id;
		$quote = $this->Quote->read();
		$quote['Quote']['status'] = QUOTE_STATUS_NORMAL;
			
		if($this->Quote->save($quote))
		{
			$this->flash('Quote undeleted.', '/' . $id);
			exit();
		}

		$this->flash('Error undeleting quote.', '/' . $id);
	}

	function unapproved()
	{
		$this->checkLock();
		$this->checkRights();
		
		$quotes = $this->Quote->findAll("status = '" . QUOTE_STATUS_UNAPPROVED . "'", null, 'Quote.id DESC');
		
		foreach($quotes as &$quote)
		{
			$quote = $this->sanitize($quote);
		}
		
		$this->set('header', 'Unapproved quotes');
		$this->set('title', 'Unapproved quotes');
		$this->set('mode', 'unapproved');
		$this->set('quotes', $quotes);
		$this->render('index');
	}

	function bioreactor()
	{
		$quotes = $this->Quote->findAll("status = '" . QUOTE_STATUS_DELETED . "'", null, 'deleted DESC', QDB_BIOREACTOR_COUNT);
			
		foreach($quotes as &$quote)
		{
			$quote = $this->sanitize($quote);
		}
		
		$this->set('header', 'Last ' . QDB_BIOREACTOR_COUNT . ' deleted quotes');
		$this->set('title', 'Bioreactor');
		$this->set('quotes', $quotes);
		$this->set('bioreactor', true);
		$this->render('index');
	}

	function fortunes()
	{
		header('Content-type: text/plain; charset=utf-8');
		header('Content-disposition: inline; filename=fortunes.txt');

		$cond = "status = '" . QUOTE_STATUS_NORMAL . "'";
		$quotes = $this->Quote->findAll($cond);
		$this->layout = 'blank';
		
		$this->set('quotes', $quotes);
		$this->render('fortune');
	}
	
	function opensearch()
	{
        header('Content-type: application/opensearchdescription+xml; charset=utf-8');
	}
}

?>
